//==========================================================================
// Copyright (c) 2000-2006,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <winhack.h>
#include <eltypes.h>
#include "convert.h"
#include <string.h>
#include <stdio.h>
#include <eventman.h>

//#define _DBG_RTC

EXTERN_C void GetAlarmTime(SystemTime *time);
EXTERN_C void SetAlarmTime(SystemTime time);
EXTERN_C void SaveVMtimeInFile(void);
EXTERN_C void ReadVMtimeFromFile(void);
EXTERN_C void SetIsAlarm(bool flag);
EXTERN_C bool IsAlarm();

void getVMtimeSys(PSYSTEMTIME pSystime)
{
    SystemTime stdTime;
    SystemTime sysTime;
    GetSystemTime(pSystime);
    ConvertSystimeToEzTime(*pSystime, &stdTime);
    ConvertSYStimeToVMtime(stdTime, &sysTime);
    ConvertEzTimeToSystime(sysTime, pSystime);
}

void setVMtimeSys(SYSTEMTIME setSystime)
{
    SystemTime stdTime;
    SystemTime time;
    SYSTEMTIME stdSystime;
    ConvertSystimeToEzTime(setSystime, &time);
    GetSystemTime(&stdSystime);
    ConvertSystimeToEzTime(stdSystime, &stdTime);
    ConvertVMtimeToDiffTime(stdTime, time);
}

typedef struct {
    UINT8 uYear;
    UINT8 uMonth;
    UINT8 uDay;
    UINT8 uHour;
    UINT8 uMinute;
    UINT8 uSecond;
    UINT8 uWeekDay;
    UINT8 Reserved2;
}PackTime;

void sendTimeUpdateEvent()
{
    PackTime t;
    SYSTEMTIME systime;
    getVMtimeSys(&systime);

    EmIsrParameter Param;
    Param.nParameter1 = Param.nParameter2 = 0;
    Param.nParameter3 = Param.nParameter4 = 0;

    t.uYear = (UINT8)(systime.wYear-2000);
    t.uMonth = (UINT8)systime.wMonth;
    t.uDay = (UINT8)systime.wDay;
    t.uHour = (UINT8)systime.wHour;
    t.uMinute = (UINT8)systime.wMinute;
    t.uSecond = (UINT8)systime.wSecond;
    t.uWeekDay = (UINT8)systime.wDayOfWeek;
    t.Reserved2 = 0;
#ifdef _DBG_RTC
    printf("TimeChange at %d:%d:%d %d:%d:%d\n",
        t.uYear, t.uMonth, t.uDay, t.uHour, t.uMinute, t.uSecond);
#endif
    memcpy(&Param, &t, sizeof(PackTime));
    EmPostEventByIsr(114, &Param);//time change event

    //send time change Event;
}

void sendAlarmEvent()
{
    PackTime t;
    SYSTEMTIME systime;
    getVMtimeSys(&systime);

#ifdef _DBG_RTC
    printf("alarm at %d:%d:%d %d:%d:%d\n",
        systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond);
#endif
    EmIsrParameter Param;
    Param.nParameter1 = Param.nParameter2 = 0;
    Param.nParameter3 = Param.nParameter4 = 0;

    t.uYear = (UINT8)(systime.wYear-2000);
    t.uMonth = (UINT8)systime.wMonth;
    t.uDay = (UINT8)systime.wDay;
    t.uHour = (UINT8)systime.wHour;
    t.uMinute = (UINT8)systime.wMinute;
    t.uSecond = (UINT8)systime.wSecond;
    t.uWeekDay = (UINT8)systime.wDayOfWeek;
    t.Reserved2 = 0;
#ifdef _DBG_RTC
    printf("alarm at %d:%d:%d %d:%d:%d\n",
        t.uYear, t.uMonth, t.uDay, t.uHour, t.uMinute, t.uSecond);
#endif
    memcpy(&Param, &t, sizeof(PackTime));
    EmPostEventByIsr(113, &Param);//rtc alarm event
}

DWORD __stdcall alarmThread(LPVOID para)
{
    while(IsAlarm()){
        SystemTime runTime;
        SystemTime alarmTime;
        SystemTime temptime;
        SYSTEMTIME systime;

        GetSystemTime(&systime);
        ConvertSystimeToEzTime(systime, &temptime);
        ConvertSYStimeToVMtime(temptime, &runTime);

        GetAlarmTime(&alarmTime);
#ifdef _DBG_RTC
        printf("Now time %d\n", runTime.seconds);
        printf("alarm time %d\n", alarmTime.seconds);
#endif

        if (runTime.seconds == alarmTime.seconds) {
#ifdef _DBG_RTC
            printf("Alarm!!!!!!!!time:%d\n", runTime.seconds);
#endif
            sendAlarmEvent();
        }

        WaitForSingleObject(g_TimeConver.hAlarmEvent, 1000);
    }

    return 0;
}

EXTERN_C ECode RTCEnableAlarm()
{
    //setup a thread to check out the time alarm
    if(IsAlarm()){
        return NOERROR;
    }
    SetIsAlarm(true);
    if (NULL == g_TimeConver.hAlarmEvent) {
        g_TimeConver.hAlarmEvent = CreateEventW(NULL, false, false, NULL);
        if(NULL == g_TimeConver.hAlarmEvent) {
            printf("Create AlarmEvent ERR, alarm enable fail\n");
            return E_ACCESS_DENIED;
        }
    }
    CreateThread(
        NULL, 0, alarmThread, 0, 0, NULL);
    return NOERROR;
}

EXTERN_C ECode RTCDisableAlarm()
{
    SetIsAlarm(false);
    if(NULL != g_TimeConver.hAlarmEvent) {
        SetEvent(g_TimeConver.hAlarmEvent);
        CloseHandle(g_TimeConver.hAlarmEvent);
        g_TimeConver.hAlarmEvent = NULL;
    }
    return NOERROR;
}


EXTERN_C ECode RTCReadTime(int *hour, int *min, int *second)
{
    SYSTEMTIME  systime;
    getVMtimeSys(&systime);
    *hour = (int)systime.wHour;
    *min = (int)systime.wMinute;
    *second = (int)systime.wSecond;
//    printf("RTCReadTime hour:%d, min:%d, second:%d\n", hour, min, second);
    return NOERROR;
}

EXTERN_C ECode RTCReadDate(int *week, int *year, int *month, int *date)
{
    SYSTEMTIME  systime;
    getVMtimeSys(&systime);
    *year = (int)(systime.wYear-2000);
    *month = (int)systime.wMonth;
    *week = (int)systime.wDayOfWeek;
    *date = (int)systime.wDay;
//    printf("Read RTCReadDate year:%d, month:%d, day:%d\n", year, month, date);
    return NOERROR;
}

EXTERN_C ECode RTCReadDateAndTime(MemoryBuf * pOutData)
{
    SYSTEMTIME  systime;
    getVMtimeSys(&systime);

    UInt32 weekday = (int)systime.wDayOfWeek;
	UInt32 year = (int)(systime.wYear-2000);
	UInt32 month = (int)systime.wMonth;
	UInt32 day = (int)systime.wDay;
	UInt32 hour = (int)systime.wHour;
	UInt32 minute = (int)systime.wMinute;
	UInt32 second = (int)systime.wSecond;

    pOutData->Copy((Byte *)&weekday, 4);
    pOutData->Append((Byte *)&year, 4);
    pOutData->Append((Byte *)&month, 4);
    pOutData->Append((Byte *)&day, 4);
    pOutData->Append((Byte *)&hour, 4);
    pOutData->Append((Byte *)&minute, 4);
    pOutData->Append((Byte *)&second, 4);
    pOutData->SetUsed(28);

    return NOERROR;
}

EXTERN_C ECode RTCReadAlarmTime(int *hour, int *min, int *second)
{
    SystemTime time;
    SYSTEMTIME  systime;
    GetAlarmTime(&time);
    ConvertEzTimeToSystime(time, &systime);
    *hour = (int)systime.wHour;
    *min = (int)systime.wMinute;
    *second = (int)systime.wSecond;
//    printf("RTCReadAlarmTime hour:%d, min:%d, second:%d\n", hour, min, second);
    return NOERROR;
}

EXTERN_C ECode RTCReadAlarmDate(int *week, int *year, int *month, int *date)
{
    SystemTime time;
    SYSTEMTIME  systime;
    GetAlarmTime(&time);
    ConvertEzTimeToSystime(time, &systime);
    *year = (int)(systime.wYear-2000);
    *month = (int)systime.wMonth;
    *week = (int)systime.wDayOfWeek;
    *date = (int)systime.wDay;
//    printf("Read RTCReadAlarmDate year:%d, month:%d, day:%d\n", year, month, date);
    return NOERROR;
}

EXTERN_C ECode RTCReadAlarmDateAndTime(MemoryBuf * pOutData)
{
    SystemTime time;
    SYSTEMTIME  systime;
    GetAlarmTime(&time);
    ConvertEzTimeToSystime(time, &systime);

    UInt32 weekday = (int)systime.wDayOfWeek;
	UInt32 year = (int)(systime.wYear-2000);
	UInt32 month = (int)systime.wMonth;
	UInt32 day = (int)systime.wDay;
	UInt32 hour = (int)systime.wHour;
	UInt32 minute = (int)systime.wMinute;
	UInt32 second = (int)systime.wSecond;

    pOutData->Copy((Byte *)&weekday, 4);
    pOutData->Append((Byte *)&year, 4);
    pOutData->Append((Byte *)&month, 4);
    pOutData->Append((Byte *)&day, 4);
    pOutData->Append((Byte *)&hour, 4);
    pOutData->Append((Byte *)&minute, 4);
    pOutData->Append((Byte *)&second, 4);
    pOutData->SetUsed(28);
    return NOERROR;
}

EXTERN_C ECode RTCSettime(int hour, int min, int second)
{
    SYSTEMTIME  systime;
    getVMtimeSys(&systime);
    systime.wHour =hour;
    systime.wMinute = min;
    systime.wSecond = second;
//    printf("RTCSettime hour:%d, min:%d, second:%d\n", hour, min, second);
    setVMtimeSys(systime);
    sendTimeUpdateEvent();
    SaveVMtimeInFile();
    return NOERROR;
}

EXTERN_C ECode RTCSetdate(int week, int year, int month, int date)
{
    SYSTEMTIME  systime;
    getVMtimeSys(&systime);
    year += 2000;
    if((year < 2000) || (year > 2037)) {
        return E_ACCESS_DENIED;
    }
    systime.wYear = year;
    systime.wMonth = month;
    systime.wDayOfWeek = week;
    systime.wDay = date;
//    printf("set RTCSetdate year:%d, month:%d, day:%d\n", year, month, date);
    setVMtimeSys(systime);
    sendTimeUpdateEvent();
    SaveVMtimeInFile();
    return NOERROR;
}

EXTERN_C ECode RTCSetdatetime(SystemTime *pSystemTime)
{
    SystemTime stdTime;
    SYSTEMTIME stdSystime;
    GetSystemTime(&stdSystime);
    ConvertSystimeToEzTime(stdSystime, &stdTime);
    ConvertVMtimeToDiffTime(stdTime, *pSystemTime);
    sendTimeUpdateEvent();
    SaveVMtimeInFile();
    return NOERROR;
}

EXTERN_C ECode RTCSetAlarmtime(int hour, int min, int second)
{
    SYSTEMTIME  systime;
    SystemTime time;
    GetAlarmTime(&time);
    ConvertEzTimeToSystime(time, &systime);
    systime.wHour =hour;
    systime.wMinute = min;
    systime.wSecond = second;
//    printf("RTCSetAlarmtime hour:%d, min:%d, second:%d\n", hour, min, second);
    ConvertSystimeToEzTime(systime, &time);
    SetAlarmTime(time);
    SaveVMtimeInFile();

    return NOERROR;
}

EXTERN_C ECode RTCSetAlarmdate(int week, int year, int month, int date)
{
    SYSTEMTIME  systime;
    SystemTime time;
    GetAlarmTime(&time);
    ConvertEzTimeToSystime(time, &systime);
    year += 2000;
    if((year < 2000) || (year > 2037)) {
        return E_ACCESS_DENIED;
    }
    systime.wYear = year;
    systime.wMonth = month;
    systime.wDayOfWeek = week;
    systime.wDay = date;
//    printf("set RTCSetAlarmdate year:%d, month:%d, day:%d\n", year, month, date);
    ConvertSystimeToEzTime(systime, &time);
    SetAlarmTime(time);
    SaveVMtimeInFile();

    return NOERROR;
}
#define   WEEKDAY  0
#define   YEAR     1
#define   MONTH    2
#define   DAY      3
#define   HOUR     4
#define   MINUTE   5
#define   SECOND   6

EXTERN_C ECode RTCSetAlarmDateAndTime(int *p)
{
    SYSTEMTIME  systime;
    SystemTime time;

    if ((p[WEEKDAY] < 0 || p[WEEKDAY] > 6) || (p[YEAR] < 0 || p[YEAR] > 99) ||
        (p[MONTH] < 1 || p[MONTH] > 12) || (p[DAY] < 1 || p[DAY] > 31) ||
        (p[HOUR] < 0 || p[HOUR] > 23) || (p[MINUTE] < 0 || p[MINUTE] > 59) ||
        (p[SECOND] < 0 || p[SECOND] > 59)) {
        return E_INVALID_ARGUMENT;
    }

    systime.wYear = p[YEAR];


	systime.wYear += 2000;
    if((systime.wYear < 2000) || (systime.wYear > 2037)) {
        return E_ACCESS_DENIED;
    }
    systime.wMonth = p[MONTH];
	systime.wDay = p[DAY];

    systime.wDayOfWeek = p[WEEKDAY];

    systime.wHour = p[HOUR];
	systime.wMinute = p[MINUTE];
	systime.wSecond = p[SECOND];
//    printf("%d, %d, %d, %d, %d, %d ,%d\n", systime.wDayOfWeek, systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond);
    ConvertSystimeToEzTime(systime, &time);
    SetAlarmTime(time);
    SaveVMtimeInFile();
    return NOERROR;
}

EXTERN_C void RTCInit()
{
    SetIsAlarm(false);
    ReadVMtimeFromFile();
}

EXTERN_C void RTCDispose()
{
    SaveVMtimeInFile();
}
